use chrono::{Local, TimeZone};
use std::hint::spin_loop;
use std::sync::{LazyLock, Mutex};
use std::time::{SystemTime, UNIX_EPOCH};

#[derive(Copy, Clone, Debug)]
pub struct SnowflakeIdGenerator {
    epoch: SystemTime,
    last_time_millis: u32,
    pub instance_id: u8, // 只有后两位有效，所以取值范围0,1,2,3
    idx: u8,
}

impl SnowflakeIdGenerator {
    #[inline(always)]
    /// Get the latest milliseconds of the clock.
    fn get_time_millis(epoch: SystemTime) -> u32 {
        let millis = SystemTime::now()
            .duration_since(epoch)
            .expect("Time went mackward")
            .as_millis();
        (millis & 0xFFFFFFFF) as u32
    }

    #[inline(always)]
    // Constantly refreshing the latest milliseconds by busy waiting.
    fn biding_time_conditions(last_time_millis: u32, epoch: SystemTime) -> u32 {
        let mut latest_time_millis: u32;
        loop {
            latest_time_millis = Self::get_time_millis(epoch);
            if latest_time_millis > last_time_millis {
                return latest_time_millis;
            }
            spin_loop();
        }
    }
    pub fn new(node_id: u8) -> Self {
        Self::with_epoch(node_id, UNIX_EPOCH)
    }
    pub fn with_epoch(node_id: u8, epoch: SystemTime) -> Self {
        //TODO:limit the maximum of input args machine_id and node_id
        let last_time_millis = Self::get_time_millis(epoch);
        SnowflakeIdGenerator {
            epoch,
            last_time_millis,
            instance_id: node_id,
            idx: 0,
        }
    }
    pub fn real_time_generate(&mut self) -> u64 {
        self.idx = (self.idx + 1) % u8::MAX;
        let mut now_millis = Self::get_time_millis(self.epoch);
        if now_millis == self.last_time_millis {
            if self.idx == 0 {
                now_millis = Self::biding_time_conditions(self.last_time_millis, self.epoch);
                self.last_time_millis = now_millis;
            }
        } else {
            self.last_time_millis = now_millis;
            self.idx = 0;
        }
        self.bit_run()
    }
    pub fn generate(&mut self) -> u64 {
        self.idx = (self.idx + 1) % u8::MAX;
        if self.idx == 0 {
            let mut now_millis = Self::get_time_millis(self.epoch);
            if now_millis == self.last_time_millis {
                now_millis = Self::biding_time_conditions(self.last_time_millis, self.epoch);
            }
            self.last_time_millis = now_millis;
        }
        self.bit_run()
    }
    pub fn lazy_generate(&mut self) -> u64 {
        self.idx = (self.idx + 1) % u8::MAX;
        if self.idx == 0 {
            self.last_time_millis += 1;
        }
        self.bit_run()
    }
    fn bit_run(&mut self) -> u64 {
        (self.last_time_millis << 11) as u64 | (self.instance_id as u64) << 8 | (self.idx as u64)
    }
}

pub static ID_FACTORY: LazyLock<Mutex<SnowflakeIdGenerator>> = LazyLock::new(|| {
    let begin_ts = Local.with_ymd_and_hms(2024, 1, 1, 0, 0, 0).unwrap();
    let id_factory = SnowflakeIdGenerator::with_epoch(0, SystemTime::from(begin_ts));
    Mutex::new(id_factory)
});
